﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.RegularExpressions;
using DACU.Properties;

namespace DACU.Tools.JavaScript
{
	internal class JavaScriptObjectDeserializer
	{
		// Fields
		private int _depthLimit;
		internal JavaScriptString _s;
		private JavaScriptSerializer _serializer;
		private const string DateTimePrefix = "\"\\/Date(";
		private const int DateTimePrefixLength = 8;

		// Methods
		private JavaScriptObjectDeserializer(string input, int depthLimit, JavaScriptSerializer serializer)
		{
			_s = new JavaScriptString(input);
			_depthLimit = depthLimit;
			_serializer = serializer;
		}

		private void AppendCharToBuilder(char? c, StringBuilder sb)
		{
			switch (c)
			{
				case '/':
				case '\'':
				case '"':
					sb.Append(c);
					break;
				case 'b':
					sb.Append('\b');
					break;
				case 'f':
					sb.Append('\f');
					break;
				case 'n':
					sb.Append('\n');
					break;
				case 'r':
					sb.Append('\r');
					break;
				case 't':
					sb.Append('\t');
					break;
				default:
					if (c != 'u')
						throw new ArgumentException(_s.GetDebugString(Resources.JSON_BadEscape));
					sb.Append((char)int.Parse(_s.MoveNext(4), NumberStyles.HexNumber, CultureInfo.InvariantCulture));
					break;
			}
		}

		internal static object BasicDeserialize(string input, int depthLimit, JavaScriptSerializer serializer)
		{
			var deserializer = new JavaScriptObjectDeserializer(input, depthLimit, serializer);
			object obj2 = deserializer.DeserializeInternal(0);
			char? nextNonEmptyChar = deserializer._s.GetNextNonEmptyChar();
			int? nullable3 = nextNonEmptyChar.HasValue ? new int?(nextNonEmptyChar.GetValueOrDefault()) : null;
			if (nullable3.HasValue)
				throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.JSON_IllegalPrimitive, new object[] {deserializer._s.ToString()}));
			return obj2;
		}

		private char CheckQuoteChar(char? c)
		{
			if (c == '\'')
				return c.Value;
			if (c != '"')
				throw new ArgumentException(_s.GetDebugString(Resources.JSON_StringNotQuoted));
			return '"';
		}

		private IDictionary<string, object> DeserializeDictionary(int depth)
		{
			IDictionary<string, object> dictionary = null;
			char? nextNonEmptyChar;
			char? nullable8;
			char? nullable11;
			if (_s.MoveNext() != '{')
				throw new ArgumentException(_s.GetDebugString(Resources.JSON_ExpectedOpenBrace));
		Label_018D:
			nullable8 = nextNonEmptyChar = _s.GetNextNonEmptyChar();
			int? nullable10 = nullable8.HasValue ? new int?(nullable8.GetValueOrDefault()) : null;
			if (nullable10.HasValue)
			{
				_s.MovePrev();
				if (nextNonEmptyChar == ':')
					throw new ArgumentException(_s.GetDebugString(Resources.JSON_InvalidMemberName));
				string str = null;
				if (nextNonEmptyChar != '}')
				{
					str = DeserializeMemberName();
					if (string.IsNullOrEmpty(str))
						throw new ArgumentException(_s.GetDebugString(Resources.JSON_InvalidMemberName));
					if (_s.GetNextNonEmptyChar() != ':')
						throw new ArgumentException(_s.GetDebugString(Resources.JSON_InvalidObject));
				}
				if (dictionary == null)
				{
					dictionary = new Dictionary<string, object>();
					if (string.IsNullOrEmpty(str))
					{
						nextNonEmptyChar = _s.GetNextNonEmptyChar();
						goto Label_01CB;
					}
				}
				object obj2 = DeserializeInternal(depth);
				dictionary[str] = obj2;
				nextNonEmptyChar = _s.GetNextNonEmptyChar();
				if (nextNonEmptyChar != '}')
				{
					if (nextNonEmptyChar != ',')
						throw new ArgumentException(_s.GetDebugString(Resources.JSON_InvalidObject));
					goto Label_018D;
				}
			}
		Label_01CB:
			nullable11 = nextNonEmptyChar;
			if ((nullable11.GetValueOrDefault() != '}') || !nullable11.HasValue)
				throw new ArgumentException(_s.GetDebugString(Resources.JSON_InvalidObject));
			return dictionary;
		}

		private object DeserializeInternal(int depth)
		{
			if (++depth > _depthLimit)
			{
				throw new ArgumentException(_s.GetDebugString(Resources.JSON_DepthLimitExceeded));
			}
			char? nextNonEmptyChar = _s.GetNextNonEmptyChar();
			char? nullable2 = nextNonEmptyChar;
			int? nullable4 = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault()) : null;
			if (!nullable4.HasValue)
				return null;
			_s.MovePrev();
			if (IsNextElementDateTime())
				return DeserializeStringIntoDateTime();
			if (IsNextElementObject(nextNonEmptyChar))
			{
				IDictionary<string, object> o = DeserializeDictionary(depth);
				return o.ContainsKey("__type") ? ObjectConverter.ConvertObjectToType(o, null, _serializer) : o;
			}
			if (IsNextElementArray(nextNonEmptyChar))
				return DeserializeList(depth);
			if (IsNextElementString(nextNonEmptyChar))
				return DeserializeString();
			return DeserializePrimitiveObject();
		}

		private IList DeserializeList(int depth)
		{
			char? nextNonEmptyChar;
			char? nullable5;
			IList list = new ArrayList();
			if (_s.MoveNext() != '[')
				throw new ArgumentException(_s.GetDebugString(Resources.JSON_InvalidArrayStart));
			bool flag = false;
		Label_00C4:
			nullable5 = nextNonEmptyChar = _s.GetNextNonEmptyChar();
			int? nullable7 = nullable5.HasValue ? new int?(nullable5.GetValueOrDefault()) : null;
			if (nullable7.HasValue && (nextNonEmptyChar != ']'))
			{
				_s.MovePrev();
				object obj2 = DeserializeInternal(depth);
				list.Add(obj2);
				flag = false;
				nextNonEmptyChar = _s.GetNextNonEmptyChar();
				if (nextNonEmptyChar != ']')
				{
					flag = true;
					if (nextNonEmptyChar != ',')
						throw new ArgumentException(_s.GetDebugString(Resources.JSON_InvalidArrayExpectComma));
					goto Label_00C4;
				}
			}
			if (flag)
				throw new ArgumentException(_s.GetDebugString(Resources.JSON_InvalidArrayExtraComma));
			if (nextNonEmptyChar != ']')
				throw new ArgumentException(_s.GetDebugString(Resources.JSON_InvalidArrayEnd));
			return list;
		}

		private string DeserializeMemberName()
		{
			char? nextNonEmptyChar = _s.GetNextNonEmptyChar();
			char? nullable2 = nextNonEmptyChar;
			int? nullable4 = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault()) : null;
			if (!nullable4.HasValue)
				return null;
			_s.MovePrev();
			return IsNextElementString(nextNonEmptyChar) ? DeserializeString() : DeserializePrimitiveToken();
		}

		private object DeserializePrimitiveObject()
		{
			double num4;
			string s = DeserializePrimitiveToken();
			if (s.Equals("null"))
				return null;
			if (s.Equals("true"))
				return true;
			if (s.Equals("false"))
				return false;
			bool flag = s.IndexOf('.') >= 0;
			if (s.LastIndexOf("e", StringComparison.OrdinalIgnoreCase) < 0)
			{
				decimal num3;
				if (!flag)
				{
					int num;
					long num2;
					if (int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out num))
						return num;
					if (long.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out num2))
						return num2;
				}
				if (decimal.TryParse(s, NumberStyles.Number, CultureInfo.InvariantCulture, out num3))
					return num3;
			}
			if (!double.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out num4))
				throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Resources.JSON_IllegalPrimitive, new object[] {s}));
			return num4;
		}

		private string DeserializePrimitiveToken()
		{
			char? nullable2;
			var builder = new StringBuilder();
			char? nullable = null;
		Label_0066:
			nullable2 = nullable = _s.MoveNext();
			int? nullable4 = nullable2.HasValue ? new int?(nullable2.GetValueOrDefault()) : null;
			if (nullable4.HasValue)
			{
				if ((char.IsLetterOrDigit(nullable.Value) || (nullable.Value == '.')) || (((nullable.Value == '-') || (nullable.Value == '_')) || (nullable.Value == '+')))
					builder.Append(nullable);
				else
				{
					_s.MovePrev();
					goto Label_00A2;
				}
				goto Label_0066;
			}
		Label_00A2:
			return builder.ToString();
		}

		private string DeserializeString()
		{
			var sb = new StringBuilder();
			bool flag = false;
			char? c = _s.MoveNext();
			char ch = CheckQuoteChar(c);
			while (true)
			{
				char? nullable4 = c = _s.MoveNext();
				int? nullable6 = nullable4.HasValue ? new int?(nullable4.GetValueOrDefault()) : null;
				if (!nullable6.HasValue)
				{
					throw new ArgumentException(_s.GetDebugString(Resources.JSON_UnterminatedString));
				}
				if (c == '\\')
				{
					if (flag)
					{
						sb.Append('\\');
						flag = false;
					}
					else
						flag = true;
				}
				else
					if (flag)
					{
						AppendCharToBuilder(c, sb);
						flag = false;
					}
					else
					{
						char? nullable3 = c;
						int num = ch;
						if ((nullable3.GetValueOrDefault() == num) && nullable3.HasValue)
							return sb.ToString();
						sb.Append(c);
					}
			}
		}

		private object DeserializeStringIntoDateTime()
		{
			long num;
			Match match = Regex.Match(_s.ToString(), "^\"\\\\/Date\\((?<ticks>-?[0-9]+)(?:[a-zA-Z]|(?:\\+|-)[0-9]{4})?\\)\\\\/\"");
			if (long.TryParse(match.Groups["ticks"].Value, out num))
			{
				_s.MoveNext(match.Length);
				return new DateTime((num * 0x2710L) + JavaScriptSerializer.DatetimeMinTimeTicks, DateTimeKind.Utc);
			}
			return DeserializeString();
		}

		private static bool IsNextElementArray(char? c)
		{
			return (c == '[');
		}

		private bool IsNextElementDateTime()
		{
			string a = _s.MoveNext(8);
			if (a == null)
				return false;
			_s.MovePrev(8);
			return string.Equals(a, "\"\\/Date(", StringComparison.Ordinal);
		}

		private static bool IsNextElementObject(char? c)
		{
			return (c == '{');
		}

		private static bool IsNextElementString(char? c)
		{
			return ((c == '"') || (c == '\''));
		}
	}
}
